package com.yc.sole.system.repository;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.sole.common.constant.CacheConstant;
import com.yc.sole.common.enums.CommonState;
import com.yc.sole.common.enums.UserType;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.mybatis.page.Paging;
import com.yc.sole.framework.mybatis.util.PageUtil;
import com.yc.sole.framework.redis.RedissonService;
import com.yc.sole.framework.redis.enums.CacheTime;
import com.yc.sole.system.dto.MenuDto;
import com.yc.sole.system.dto.UserDto;
import com.yc.sole.system.entity.User;
import com.yc.sole.system.exception.SysResultEnum;
import com.yc.sole.system.mapper.UserMapper;
import com.yc.sole.system.request.UserQueryReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务接口实现
 *
 * @author yizuomin
 * @date 2023-03-26
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class UserRepository extends ServiceImpl<UserMapper, User> {

    private final UserRoleRepository userRoleRepository;
    private final RoleMenuRepository roleMenuRepository;
    private final MenuRepository menuRepository;
    private final RedissonService redissonService;

    /**
     * 新增
     *
     * @param userDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public Long saveUser(UserDto userDto) {
        User entity = new User();
        BeanUtil.copyProperties(userDto, entity);
        this.save(entity);
        redissonService.hRemoveAll(CacheConstant.AUTH_USER_CACHE_MAP);
        return entity.getId();
    }

    /**
     * 通过Id修改
     *
     * @param userDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateUserById(UserDto userDto) {
        redissonService.hRemove(CacheConstant.AUTH_USER_CACHE_MAP, userDto.getId(), () -> {
            User entity = new User();
            BeanUtil.copyProperties(userDto, entity);
            this.updateById(entity);
        });
    }

    /**
     * 通过id删除
     *
     * @param ids
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteUserByIds(Collection<Long> ids) {
        List<UserDto> userDtos = this.selectUserByIds(ids);
        for (UserDto userDto : userDtos) {
            if (UserType.SYSTEM_USER.equals(userDto.getUserType())) {
                throw new BaseException(SysResultEnum.SYSTEM_USER_CANNOT_DELETE);
            }
        }
        this.removeBatchByIds(ids);
        redissonService.hRemoveAll(CacheConstant.AUTH_USER_CACHE_MAP);
    }

    /**
     * 根据id获取
     *
     * @param id
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public UserDto selectUserById(Long id) {
        return redissonService.hCache(CacheConstant.AUTH_USER_CACHE_MAP, id, CacheTime.ONE_DAY, () -> BeanUtil.copyProperties(this.getById(id), UserDto.class));
    }

    /**
     * 根据id获取
     *
     * @param ids
     * @return
     */
    public List<UserDto> selectUserByIds(Collection<Long> ids) {
        List<UserDto> userDtoList = ids.stream().map(this::selectUserById).collect(Collectors.toList());
        return BeanUtil.copyToList(userDtoList, UserDto.class);
    }

    /**
     * 根据用户名查询用户id
     *
     * @param username
     * @return
     */
    public Long selectUserIdByUsername(String username) {
        User user = this.getOne(Wrappers.<User>lambdaQuery().select(User::getId).eq(User::getUsername, username));
        if (Objects.isNull(user)) {
            return null;
        }
        return user.getId();
    }

    /**
     * 根据用户名或手机号查询
     *
     * @param username
     * @return
     */
    public UserDto selectByUsernameOrPhone(String username) {
        LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery()
                .eq(User::getUsername, username)
                .or()
                .eq(User::getPhoneNum, username);
        UserDto userDto = BeanUtil.copyProperties(this.getOne(wrapper), UserDto.class);
        if (Objects.isNull(userDto)) {
            throw new BaseException(SysResultEnum.AUTH_USER_NOT_FOUND);
        }

        List<Long> roleIds = userRoleRepository.selectRoleIdsByUserId(userDto.getId());
        if (CollUtil.isEmpty(roleIds)) {
            return userDto;
        }
        userDto.setRoleIds(roleIds);
        if (UserType.USER.equals(userDto.getUserType())) {
            Set<Long> menuIds = roleMenuRepository.selectMenuIdByRoleIds(roleIds);
            List<MenuDto> menuDtoList = menuRepository.selectEnableMenuByIds(menuIds);
            userDto.setMenus(menuDtoList);
        } else {
            List<MenuDto> menuDtoList = menuRepository.selectAllEnableMenus();
            userDto.setMenus(menuDtoList);
        }
        return userDto;
    }

    /**
     * 校验用户名是否存在
     *
     * @param username
     * @return
     */
    public boolean existByUsernameOrPhone(String username) {
        LambdaQueryWrapper<User> eq = Wrappers.<User>lambdaQuery()
                .eq(User::getUsername, username)
                .or().eq(User::getPhoneNum, username);
        return this.count(eq) > 0;
    }

    /**
     * 查询所有用户id
     *
     * @return
     */
    public List<Long> selectAllUserId() {
        LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery().select(User::getId).eq(User::getState, CommonState.ENABLE);
        return this.list(wrapper).stream().map(User::getId).toList();
    }

    /**
     * 根据角色id查询
     *
     * @param roleIds
     * @return
     */
    public List<UserDto> selectByRoleIds(Set<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        Set<Long> userIds = userRoleRepository.selectUserIdsByRoleIds(roleIds);
        if (CollUtil.isNotEmpty(userIds)) {
            return BeanUtil.copyToList(this.listByIds(userIds), UserDto.class);
        }
        return Collections.emptyList();
    }

    /**
     * 分页查询
     *
     * @param page
     * @return RestResult
     */
    public Paging<UserDto> selectUserPage(Paging page, UserQueryReq userQueryReq) {
        LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery()
                .eq(Objects.nonNull(userQueryReq.getState()), User::getState, userQueryReq.getState())
                .eq(Objects.nonNull(userQueryReq.getDeptId()), User::getDeptId, userQueryReq.getDeptId())
                .like(CharSequenceUtil.isNotBlank(userQueryReq.getPhoneNum()), User::getPhoneNum, userQueryReq.getPhoneNum())
                .like(CharSequenceUtil.isNotBlank(userQueryReq.getUsername()), User::getUsername, userQueryReq.getUsername());
        return PageUtil.pageCopy(this.page(PageUtil.toMybatisPage(page), queryWrapper), UserDto.class);
    }
}
